﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;

namespace NiuX.Domain.Repositories
{
    public interface IQueryableProvider
    {
        bool CanExecute<T>(IQueryable<T> queryable);

        #region Contains

        bool Contains<T>(IQueryable<T> queryable, T item);

        #endregion

        #region Any/All

        bool Any<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate);

        bool All<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate);

        #endregion

        #region Count/LongCount

        int Count<T>(IQueryable<T> queryable);

        int Count<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate);

        long LongCount<T>(IQueryable<T> queryable);

        long LongCount<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate);

        #endregion

        #region First/FirstOrDefault

        T First<T>(IQueryable<T> queryable);

        T First<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate);

        T FirstOrDefault<T>(IQueryable<T> queryable);

        T FirstOrDefault<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate);

        #endregion

        #region Last/LastOrDefault

        T Last<T>(IQueryable<T> queryable);

        T Last<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate);

        T LastOrDefault<T>(IQueryable<T> queryable);

        T LastOrDefault<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate);

        #endregion

        #region Single/SingleOrDefault

        T Single<T>(IQueryable<T> queryable);

        T Single<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate);

        T SingleOrDefault<T>(IQueryable<T> queryable);

        T SingleOrDefault<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate);

        #endregion

        #region Min

        T Min<T>(IQueryable<T> queryable);

        TResult Min<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector);

        #endregion

        #region Max

        T Max<T>(IQueryable<T> queryable);

        TResult Max<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector);

        #endregion

        #region Sum

        decimal Sum(IQueryable<decimal> source);

        decimal? Sum(IQueryable<decimal?> source);

        decimal Sum<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector);

        decimal? Sum<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector);

        int Sum(IQueryable<int> source);

        int? Sum(IQueryable<int?> source);

        int Sum<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector);

        int? Sum<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector);

        long Sum(IQueryable<long> source);

        long? Sum(IQueryable<long?> source);

        long Sum<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector);

        long? Sum<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector);

        double Sum(IQueryable<double> source);

        double? Sum(IQueryable<double?> source);

        double Sum<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector);

        double? Sum<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector);

        float Sum(IQueryable<float> source);

        float? Sum(IQueryable<float?> source);

        float Sum<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector);

        float? Sum<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector);

        #endregion

        #region Average

        decimal Average(IQueryable<decimal> source);

        decimal? Average(IQueryable<decimal?> source);

        decimal Average<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector);

        decimal? Average<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector);

        double Average(IQueryable<int> source);

        double? Average(IQueryable<int?> source);

        double Average<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector);

        double? Average<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector);

        double Average(IQueryable<long> source);

        double? Average(IQueryable<long?> source);

        double Average<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector);

        double? Average<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector);

        double Average(IQueryable<double> source);

        double? Average(IQueryable<double?> source);

        double Average<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector);

        double? Average<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector);

        float Average(IQueryable<float> source);

        float? Average(IQueryable<float?> source);

        float Average<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector);

        float? Average<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector);

        #endregion

        #region ToList/Array

        List<T> ToList<T>(IQueryable<T> queryable);

        T[] ToArray<T>(IQueryable<T> queryable);

        #endregion
    }
}